package main

import (
	"fmt"
	"github.com/shopspring/decimal"
	"math"
)

/**
数据类型介绍：

	1. 基本数据类型（原生数据类型）：整型、浮点型、复数型、布尔型、字符串、字符（byte、rune）
	2. 符合数据类型（派生数据类型）：数组（array。固定长度的数组）、切片（slice。序列数组，最常用的数据类型，属于引用类型（指针类型））、
	   接口（interface）、映射（map，属于引用类型（指针类型））、函数（function）、结构体（struct）、通道（channel，属于引用类型（指针类型））、
       指针（pointer）
*/
func main() {

	/*
			一. 整型：

				1. 有符号整型（即有正负范围。例如int8的取值范围 -128 ~ 127）：int8（占一个字节即8位，所以最大值与最小值跨度256，与平台无关）、
		 		   int16（占俩个字节即16位，所以最大值与最小值跨度 65536，后面以此类推）、int32、int64、int（此时的范围取决于平台）
				2. 无符号整型（从0开始。例如uint8取值范围 0 ~ 255，与平台无关）：uint8、uint16、uint32、uint64、uint（此时的范围取决于平台）

			TIPS: uint8就是byte型，int16对应C语言的short型，int64对应C语言的long型
	*/

	// 超出数据类型范围，将报错“constant 1000 overflows int8”
	/*var xx int8 = 1000
	fmt.Println(xx)*/

	var xxx int8 = 100
	fmt.Println(xxx)
	fmt.Println(math.MaxInt8)
	// 等价于如下的位运算的结果
	fmt.Println(1<<7 - 1)
	// 等价于如下的位运算的结果
	fmt.Println(math.MinInt8)
	fmt.Println(-1 << 7)

	var uuu uint8 = 250
	fmt.Println(uuu)
	fmt.Println(math.MaxUint8)

	/*
		二. 浮点型。浮点型表示存储的数据是实数。包括 float32（占用4字节，即32位） 和 float64（占用8字节，即64位）
	*/
	var fff float32 = 33.44444
	fmt.Println(fff)
	fmt.Println(math.MaxFloat32)             // float32能获取的最大值，大约是3.4×1038
	fmt.Println(math.SmallestNonzeroFloat32) // float32能获取的最小值，大约为1.4×10-45
	var ggg float64 = 555.3356
	fmt.Println(ggg)
	fmt.Println(math.MaxFloat64)             // float64能获取的最大值，大约是1.8×10308
	fmt.Println(math.SmallestNonzeroFloat64) // float64能获取的最小值，大约为4.9×10-324

	// 浮点型计算准确性问题，可以使用 https://github.com/shopspring/decimal
	fa := decimal.NewFromFloat(100000.001)
	fb := decimal.NewFromFloat(1.0001)
	fc := decimal.NewFromFloat(1.0002)
	fmt.Println(fa.Mul(fb.Add(fc)))

	/*
		三. 复数型。复数型用于表示数学中的复数，如1+2j、1-2j、-1-2j等。
			1. complex64。64位复数型，由float32类型的实部和虚部联合表示
			2. complex128。128位复数型，由float64类型的实部和虚部联合表示
	*/
	var c complex64 = -55 + 44i
	fmt.Println(c)

	/*
		四. 布尔型。布尔型无法参与数值运算，也无法与其他类型进行转换, 布尔型的值只可以是常量true或者false
	*/
	var b bool
	fmt.Println(b) //	如果没有给布尔变量赋值，它将默认为false
	d := true
	fmt.Println(d)

	/*
		五. 字符串

			1. 有些字符串没有现成的文字代号，所以只能用转义字符来表示。例如：\r 表示回车，\n 表示换行， \' 表示单引号等
			2. 定义多行字符串的方法：
		       · 双引号书写字符串被称为字符串字面量（string literal），这种字面量不能跨行
		       · 多行字符串需要使用反引号“`”，多用于内嵌源码和内嵌数据
		       · 在反引号中的所有代码不会被编译器识别，而只是作为字符串的一部分
	*/
	var str string = "hello world"
	fmt.Println(str)
	var omitStr = "省略数据类型"
	fmt.Println(omitStr)
	simpleStr := "自动判断类型"
	fmt.Println(simpleStr)
	// 定义多行字符串
	var temp string = `
var str string = "hello world"
fmt.Println(str)
var omitStr = "省略数据类型"
fmt.Println(omitStr)
simpleStr := "自动判断类型"
fmt.Println(simpleStr)`
	fmt.Println(temp)

	/*
		六. 字符。字符串中的每一个元素叫作“字符”，定义字符时使用单引号，类型有两种：

			1. byte：1个字节8位。表示UTF-8 字符串的单个字节的值，及uint8的别名类型
			2. rune: 4个字节32位。表示单个unicode字符，及int32的类型别名

		Go语言中byte和rune实质上就是uint8和int32类型。
	*/
	var vv byte = 'a'
	fmt.Println(vv)
	var vvv rune = '六'
	fmt.Println(vvv)

	// 超出数据类型范围，编译时将会报错：“constant 20845 overflows byte”
	/*var v byte = '六'
	fmt.Println(v)*/
}
